package com.max.common.task;

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.max.common.util.XMLConfig;

/**
 * 
 * 项目名称:max-project-graphics
 * 文件名称:AsyTaskManager.java
 * 文件描述:
 * 创建人员:chenyibo
 * 创建时间:2013-1-29 下午03:06:57
 * 修改人员:chenyibo
 * 修改时间:2013-1-29 下午03:06:57
 * 修改备注:
 * @version V1.0
 */
public class AsyTaskManager
{
	private static Log log = LogFactory.getLog("task");
	
    private DateFormat df_YYYYMMDDHHMMSS = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    // 任务列表。对该集合的并发访问一定要同步。
    final List<BaseTimerTask> allTask = new ArrayList<BaseTimerTask>();

    // 共享的精灵线程。所有seperate=false且daemon=true的任务由该线程规划。
    private final Timer SHARED_TIMER_DAEMON = new Timer(true);

    // 共享的普通线程。所有seperate=false且daemon=false的任务由该线程规划。
    private final Timer SHARED_TIMER_NONE_DAEMON = new Timer();

    // 后台运行的监控线程
    private Timer watchTimer = new Timer(true);

    // 后台运行的监控任务启动间隔时间
    private static final int WATCH_INTERVAL_TIME = 10000;

    /**
     * 任务管理器
     */
    private static AsyTaskManager instance = null;

    /**
     * 实现单态模式，通过getInstance()方法获取对象实例
     */
    private AsyTaskManager()
    {
    }

    /**
     * 获取任务管理器实例
     * 
     * @return 返回实例
     */
    public static synchronized AsyTaskManager getInstance()
    {
    	if(instance == null)
    		instance = new AsyTaskManager();
    	
    	return instance;
    }

    /**
     * 读取任务配置xml文件,初始化任务及线程，并启用监控线程，启用全部任务运行。
     * 
     * @param XMLPath
     *            xml所在的全路径（或相对程序路径）
     * @return boolean
     */
    public synchronized boolean init(String xmlPath)
    {
        // 停止所有任务
        for (Iterator<BaseTimerTask> taskIt = allTask.iterator(); taskIt.hasNext();)
        {
            try
            {
                BaseTimerTask btt = taskIt.next();
                btt.cancel();
                taskIt.remove();
            }
            catch (Exception ex)
            {
            	ex.printStackTrace();
            	log.info("Stop all schedualed tasks throw Exception." + ex.getMessage());
            }
            catch (Throwable thex)
            {
            	thex.printStackTrace();
            	log.info("Stop all schedualed tasks throw Throwable Exception." + thex.getMessage());
            }
        }
        
        log.info("Stop all schedualed tasks complete.");

        // 解析xml
        XMLConfig config = XMLConfig.getInstance(new File(xmlPath));

        // 返回的Map以指定子节点的值为Key
        Map<String,Map<String,String>> map = config.getAllValues("taskmanage/task", "class-name");

        // 通过循环，获取所有子节点的值。
        for (Iterator<Entry<String, Map<String, String>>> iter = map.entrySet().iterator(); iter.hasNext();)
        {
            try
            {
                final Entry<String,Map<String,String>> entry = iter.next();
                final BaseTimerTask task = createTask(entry.getValue());
                
                if (null != task)
                	schedualTask(task); // 启动任务
            }
            catch (Exception ex)
            {
            	ex.printStackTrace();
                log.info("Schedual tasks throw Exception."+ex.getMessage());
            }
            catch (Throwable thex)
            {
            	thex.printStackTrace();
            	log.info("Schedual tasks throw Throwable Exception."+thex.getMessage());
            }
        }
        // 如果任务为空
        if (allTask.isEmpty())
        {
            log.info("The task list is empty!");

            return false;
        }

        log.info("Start watch task...");

        // 启动监控任务
        watchTimer.schedule(WatchTask.getInstance(), 1000, WATCH_INTERVAL_TIME);

        log.info("Start watch task complete!");

        return true;
    }

    // 规划新任务运行。将任务加入列表，并规划Timer运行。
    synchronized public void schedualTask(final BaseTimerTask btt)
    {
        synchronized (allTask)
        {
            allTask.add(btt); // 加入任务列表
        }

        if (btt.isSeparate())
        	btt.timer = btt.isDaemon() ? new Timer(true) : new Timer();
        else
        	btt.timer = btt.isDaemon() ? SHARED_TIMER_DAEMON : SHARED_TIMER_NONE_DAEMON;

        // 规划任务运行
        if (btt.isRepeat())
        {
            try
            {
                btt.timer.schedule(btt, parseStartRunTime(btt.getStartTime(),
                        btt.getIntervalTime()),
                        btt.getIntervalTime() * 1000);
            }
            catch (Exception ex)
            {
            	ex.printStackTrace();
                log.info("The task [" + btt.getClassName() + "] schedule failed!throw Exception."+ex.getMessage());
            }
            catch (Throwable thex)
            {
            	thex.printStackTrace();
            	log.info("The task [" + btt.getClassName() + "] schedule failed!throw Throwable Exception."+thex.getMessage());
            }
        }
        else
        {
            // 对于运行时间在当前时间之前的，不运行,否则，按第一时间运行。
            if (btt.getStartTime().getTime() > System.currentTimeMillis())
            {
                try
                {
                    btt.timer.schedule(btt, btt.getStartTime());
                }
                catch (Exception ex)
                {
                	ex.printStackTrace();
                    log.info("The task [" + btt.getClassName() + "] schedule failed!throw Exception."+ex.getMessage());
                }
                catch (Throwable thex)
                {
                	thex.printStackTrace();
                    log.info("The task [" + btt.getClassName() + "] schedule failed!throw Throwable Exception."+thex.getMessage());
                }
            }
        }

        if (btt.isRun())
        {
            log.info("The task [" + btt.getTaskName()
                    + "] is schedualed at begining time ["
                    + df_YYYYMMDDHHMMSS.format(btt.getStartTime()) + "] "
                    + "with interval of [" + btt.getIntervalTime()
                    + "] second.");
        }
    }

    // 取消任务运行。并从任务列表中删除该任务
    synchronized public void cancelTask(final BaseTimerTask btt)
    {
        btt.cancel();
        synchronized (allTask)
        {
            allTask.remove(btt);
        }
    }

    /**
     * 验证输入的xml参数格式是否正确。有一个参数格式不正确，即返回false;
     * 
     * @param xmlMap
     *            验证xml参数
     * @return 成功与否
     */
    private boolean validate(Map xmlMap)
    {
        Set keySet = xmlMap.keySet();
        String[] xmlFlag =
        { "display-name", "class-name", "run-flag", "separate-flag",
                "repeat-flag", "monitor-flag", "daemon-flag", "start-datetime",
                "max-run-time", "interval-time" };
        for (int i = 0, length = xmlFlag.length; i < length; i++)
        {
            if (!keySet.contains(xmlFlag[i]))
            	return false;
        }
        
        return true;
    }

    /**
     * 根据预先定义规则的参数格式，分配形成相应的任务类。 读取任务配置文件中的某一项具体任务参数，进行重建新任务对象。
     * 
     * @param aTaskMap
     *            按预定义规则(xml配置文件)的任务格式形成的任务参数Map
     * @return boolean
     * @throws NullPointerException
     * @see init()
     */
    private BaseTimerTask createTask(Map aTaskMap)
    {
        // 若参数为null或为空，则返回false
        if (aTaskMap == null || aTaskMap.isEmpty())
        {
            log.info("Create task failed.Invalid parameter!");
            
            return null;
        }

        // 验证参数是否和预定义的是否完全一致
        if (!validate(aTaskMap))
        {
            log.info("Create task failed.Task config file parameter format error!");
            
            return null;
        }

        // 初始化基本任务
        BaseTimerTask btTask = new BaseTimerTask();
        if (!btTask.initFrmXML(aTaskMap))
        {
            log.info("Create task failed.Task init failed!");
            
            return null;
        }

        return btTask;
    }

    /**
     * 分析运行时间，以防止这种情况： 当任务第一次运行时间小于启动时的当前时间，任务管理器启动时会立即运行过去应该发生的多次任务
     * 
     * @param oriDate
     *            日期时间
     * @param interval
     *            间隔时间
     * @return 解析后的日期
     */
    private Date parseStartRunTime(Date oriDate, long interval)
    {
        Date currentDateTime = new Date(System.currentTimeMillis());

        while (oriDate.getTime() <= currentDateTime.getTime())
        	oriDate.setTime(oriDate.getTime() + interval * 1000);

        return oriDate;
    }

    
    synchronized public List<BaseTimerTask> getAllTask()
    {
        return new ArrayList<BaseTimerTask>(this.allTask);
    }

    public boolean updateFromXml(String xmlPath)
    {
        return init(xmlPath);
    }
}
